/* @flow */

import { _Set as Set, isObject } from '../util/index'
import type { SimpleSet } from '../util/index'
import VNode from '../vdom/vnode'

const seenObjects = new Set()

/**
 * Recursively traverse an object to evoke all converted
 * getters, so that every nested property inside the object
 * is collected as a "deep" dependency.
 */

/**
 * 递归 value 的所有子值来触发它们收集依赖的能力
 * @param {*} val 
 */
export function traverse (val: any) {
  _traverse(val, seenObjects)
  seenObjects.clear()
}

function _traverse (val: any, seen: SimpleSet) {
  let i, keys
  const isA = Array.isArray(val)
  // 如果它不是 Array 和 Object，或者已经被冻结了，那么直接返回
  if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) {
    return
  }
  if (val.__ob__) {
    // 拿到 val 的 dep.id，用这个 id来保证不会重复收集依赖
    const depId = val.__ob__.dep.id
    if (seen.has(depId)) {
      return
    }
    seen.add(depId)
  }
  // 如果是数组，则循环数组，将数组中的每一项递归调用 _traverse
  if (isA) {
    i = val.length
    while (i--) _traverse(val[i], seen)
  } else {
    // 如果 Object 类型的数据，则循环 Object 中的所有 key，然后执行一次读取操作，再递归子值。
    keys = Object.keys(val)
    i = keys.length
    // val[keys[i]] => 读取 key 的时候，会触发收集依赖的操作，把当前的 Watcher 收集进去。
    while (i--) _traverse(val[keys[i]], seen)
  }
}
